# frozen_string_literal: true

require "spec_helper"

RSpec.describe Gitlab::VulnerabilityScanning::DependencyScanning::FindingBuilder, feature_category: :software_composition_analysis do
  let(:now) { Time.zone.now }
  let(:ci_build) { build(:ci_build) }
  let(:sbom_source) { build(:ci_reports_sbom_source) }
  let(:security_scanner) { Gitlab::VulnerabilityScanning::SecurityScanner.fabricate }

  let(:advisory) do
    build(:vs_advisory,
      title: "Allocation of File Descriptors or Handles Without Limits or Throttling",
      description: "Minio a Allocation of Memory Without Limits or Throttling vulnerability in write-to-RAM.",
      cvss_v2: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
      cvss_v3: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      urls: ["https://nvd.nist.gov/vuln/detail/CVE-2018-1000538", "https://github.com/minio/minio/pull/5957"],
      identifiers: [
        build(:pm_identifier, type: "cve", name: "CVE-2018-1000538",
          url: "https://nvd.nist.gov/vuln/detail/CVE-2018-1000538", value: "CVE-2018-1000538")
      ],
      solution: "Unfortunately, there is no solution available yet.",
      affected_component: build(:vs_affected_component, name: 'github.com/minio/minio',
        version: 'v0.0.0-20180419184637-5a16671f721f')
    )
  end

  subject(:builder) do
    described_class.new(project: ci_build.project, pipeline: ci_build.pipeline, sbom_source: sbom_source,
      scanner: security_scanner, advisory: advisory)
  end

  describe "#finding" do
    let(:finding) { builder.finding }

    context "when cyclonedx sbom contains required gitlab:dependency_scanning properties" do
      let(:sbom_source) { build(:ci_reports_sbom_source, input_file_path: "go.mod", source_file_path: "go.mod") }

      it "does not add any errors to the report" do
        expect { builder.finding }.not_to raise_error
      end

      it "creates the links" do
        expect(finding.links).to match_array([
          have_attributes(url: "https://nvd.nist.gov/vuln/detail/CVE-2018-1000538"),
          have_attributes(url: "https://github.com/minio/minio/pull/5957")
        ])
      end

      it "creates the name" do
        expect(finding.name).to eq(advisory.title)
      end

      it "creates the description" do
        expect(finding.description).to eq(advisory.description)
      end

      it "creates the solution" do
        expect(finding.solution).to eq("Unfortunately, there is no solution available yet.")
      end

      it "creates a valid location" do
        expect(finding.location).to have_attributes(
          file_path: "go.mod",
          package_name: "github.com/minio/minio",
          package_version: "v0.0.0-20180419184637-5a16671f721f"
        )
      end

      it "creates the severity" do
        expect(finding.severity).to eq("high")
      end

      it "creates the confidence" do
        expect(finding.confidence).to eq("unknown")
      end

      it "creates the metadata version" do
        expect(finding.metadata_version).to eq("0.0.0")
      end
    end

    context "when cyclonedx does not contain required gitlab:dependency_scanning properties" do
      let(:sbom_source) { build(:ci_reports_sbom_source, input_file_path: nil, source_file_path: nil) }

      it "adds an error to the generated report" do
        expect do
          builder.finding
        end.to raise_error(
          Gitlab::VulnerabilityScanning::DependencyScanning::FindingBuilder::MissingPropertiesError,
          "Missing required gitlab:dependency_scanning CycloneDX properties")
      end
    end
  end
end
